﻿using System;
#if !NETFX_CORE
using System.Windows;
using System.Windows.Navigation;
#endif
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Interfaces.ViewModels;
using MugenMvvmToolkit.Interfaces.Views;
using MugenMvvmToolkit.Models;
using MugenMvvmToolkit.ViewModels;

namespace MugenMvvmToolkit.Infrastructure
{
#if WPF
    public partial class NavigationBootstrapper
#else
    public partial class Bootstrapper
#endif

    {
        #region Fields

        private INavigationProvider _navigationProvider;

        #endregion

        #region Implementation of IBootstrapper

        /// <summary>
        ///     Gets the root <see cref="INavigationProvider" />, if any.
        /// </summary>
        public INavigationProvider NavigationProvider
        {
            get
            {
                Should.PropertyBeNotNull(_navigationProvider, "NavigationProvider");
                return _navigationProvider;
            }
            protected set
            {
                Should.PropertyBeNotNull(value, "NavigationProvider");
                _navigationProvider = value;
            }
        }

        #endregion

        #region Properties

#if WPF
        /// <summary>
        /// Indicates that the MainWindow should use only Uri navigation.
        /// </summary>
        public bool UseUriNavigation { get; set; }
#endif
        #endregion

        #region Methods

        /// <summary>
        ///     Occurs after a NavigationProvider is initialized.
        /// </summary>
        protected virtual void OnNavigationProviderInitialized()
        {
        }

        /// <summary>
        ///     Gets the <see cref="INavigationProvider" />.
        /// </summary>
        /// <param name="navigationService">
        ///     The specified <see cref="INavigationService" />.
        /// </param>
        /// <returns>
        ///     An instance of <see cref="INavigationProvider" />.
        /// </returns>
        protected virtual INavigationProvider GetNavigationProvider(INavigationService navigationService)
        {
            Should.NotBeNull(navigationService, "navigationService");
#if !WINDOWS_PHONE
            INavigationCachePolicy cachePolicy = new DefaultNavigationCachePolicy();
#else
            INavigationCachePolicy cachePolicy = null;
#endif
            var nav = new NavigationProvider(navigationService, IocAdapter.Get<IViewModelProvider>(),
                IocAdapter.Get<IViewPageMappingProvider>(), IocAdapter.Get<IViewManager>(),
                IocAdapter.Get<IThreadManager>(), new DefaultNavigationOperationResultPolicy(), cachePolicy);
#if !WINDOWS_PHONE || !NETFX_CORE
            nav.NavigatingWithoutView += (provider, args) => Should.BeView(args.Content.GetType(), "navigated content");
#endif
            return nav;
        }

#if WPF
        private void ApplicationFirstOnNavigated(object sender, NavigationEventArgs e)
        {
            if (e.Content == null || e.Content.GetType() != _viewPageMappingItem.ViewType)
                return;
            Should.BeView(e.Content.GetType(), "navigated content");
            Application.Current.Navigated -= ApplicationFirstOnNavigated;
            var pageView = (IView)e.Content;
            var mainWindowNavService = new WindowNavigationService((NavigationWindow)Application.Current.MainWindow, UseUriNavigation, type => IocAdapter.Get(type))
                                       {
                                           RootItem = _viewPageMappingItem
                                       };
            NavigationProvider = GetNavigationProvider(mainWindowNavService);
            IocAdapter.BindToConstant(NavigationProvider);
            OnNavigationProviderInitialized();

            var viewModel = IocAdapter.Get<IViewModelProvider>().GetViewModel(_viewPageMappingItem.ViewModelType, ActivationPolicy.WithoutView);
            IocAdapter.Get<IViewManager>().InitializeView(viewModel, pageView);

            var navigableViewModel = viewModel as INavigableViewModel;
            if (navigableViewModel == null) return;
            navigableViewModel.OnNavigatedTo(new NavigationContext(_viewPageMappingItem, null, null, null, false,
                NavigationProvider, null));
        }
#endif

        private void DisposeNavigationProvider()
        {
            if (_navigationProvider == null) return;
            _navigationProvider.Dispose();
        }

        #endregion
    }
}